package fido;

import fido.torrentsite.TorrentSite;
import org.mymediadb.api.mmdb.model.Movie;
import org.mymediadb.api.mmdb.model.User;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class GuiController extends UserInterfaceWithFido {

    private final FidoGUI fidoGUI;
    private static Timer scheduledTimer = null;
    private java.util.List<JCheckBox> torrentSiteJCheckBoxes;
    private DefaultListModel downloadedModel = new DefaultListModel();
    private static final int MILLISECONDS_PER_HOUR = 60 * 60 * 1000;
    private boolean isBusy = false;
    private TorrentSites torrentSites;


    GuiController() {
        fidoGUI = new FidoGUI();
        torrentSites = TorrentSites.instance();

        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            public void run() {

                //which radio button is selected?
                String timerButton = null;
                if (fidoGUI.a1HoursRadioButton.isSelected()) {
                    timerButton = "1hours";
                } else if (fidoGUI.a3HoursRadioButton.isSelected()) {
                    timerButton = "3hours";
                } else if (fidoGUI.a12HoursRadioButton.isSelected()) {
                    timerButton = "12hours";
                } else if (fidoGUI.a24HoursRadioButton.isSelected()) {
                    timerButton = "24hours";
                } else if (fidoGUI.noTimerRadioButton.isSelected()) {
                    timerButton = "noTimer";
                }


                FidoCommonUtils.saveGeneralSettings(fidoGUI.textUserName.getText(), fidoGUI.textPassword.getText(), fidoGUI.labelSelectedDownloadLocation.getText(), timerButton, TorrentSites.instance().getAllSelectedSitesAsString());
                log("Saved settings before exitFido");
            }
        }));
        //add listener to the view
        // gui.RunNowListener(new RunNowListener());
        fidoGUI.buttonGroupListener(new TimerGroupListener());
        //Find out which group button should be selected
        String timer;
        try {
            timer = FidoCommonUtils.getPropertyValue("fido.current.timer");
        } catch (Exception e) {
            timer = "noTimer";
        }

        if (timer.equals("1hours")) {
            fidoGUI.a1HoursRadioButton.setSelected(true);
            startScheduledTimer(1);
        } else if (timer.equals("3hours")) {
            fidoGUI.a3HoursRadioButton.setSelected(true);
            startScheduledTimer(3);
        } else if (timer.equals("12hours")) {
            fidoGUI.a12HoursRadioButton.setSelected(true);
            startScheduledTimer(12);
        } else if (timer.equals("24hours")) {
            fidoGUI.a24HoursRadioButton.setSelected(true);
            startScheduledTimer(24);
        }

        fidoGUI.buttonCheckVersionListener(new CheckVersionListener());
        //gui.trackerListener(new TrackerListener());
        //get all trackers
        torrentSiteJCheckBoxes = new ArrayList<JCheckBox>();

        for (TorrentSite torrentSite : torrentSites.getAllTorrentSites()) {
            torrentSiteJCheckBoxes.add(new JCheckBox(torrentSite.getTorrentSiteAlias()));
        }
        String selectedTrackers;
        try {
            selectedTrackers = FidoCommonUtils.getPropertyValue("fido.current.trackers");
        } catch (Exception e) {
            selectedTrackers = "";
        }
        torrentSites.select(selectedTrackers);
        for (int i = 0; i < torrentSiteJCheckBoxes.size(); i++) {
            //adding listener
            final int index = i;
            torrentSiteJCheckBoxes.get(i).addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    String torrentSiteAlias = e.getActionCommand();
                    JCheckBox checkBox = torrentSiteJCheckBoxes.get(index);
                    try {
                        if (checkBox.isSelected()) {
                            if ((checkBox.isSelected()) && (!torrentSites.isConfigured(torrentSiteAlias))) {
                                torrentSites.configureWithGUI(torrentSiteAlias);
                            }
                        }
                    } catch (Exception e1) {
                        checkBox.setSelected(false);
                        log(e.getActionCommand() + " not configured");

                    } finally {
                        if (checkBox.isSelected()) {
                            torrentSites.select(torrentSiteAlias);
                        } else
                            torrentSites.deselect(torrentSiteAlias);
                    }

                }
            });
            //selecting those that are selected in settings file
            //TODO: replace by making TorrentSites tell when a site is selected
            if (torrentSites.isSelected(torrentSiteJCheckBoxes.get(i).getText())) {
                torrentSiteJCheckBoxes.get(i).setSelected(true);

            }

            fidoGUI.panelTrackers.add(torrentSiteJCheckBoxes.get(i));


        }

        fidoGUI.textUserName.setText(FidoCommonUtils.getPropertyValue("fido.mmdb.username"));
        fidoGUI.textPassword.setText(FidoCommonUtils.getPropertyValue("fido.mmdb.password"));
        if (FidoCommonUtils.getPropertyValue("fido.directory.torrents") != null) {
            fidoGUI.labelSelectedDownloadLocation.setText(FidoCommonUtils.getPropertyValue("fido.directory.torrents"));
        }

        // FidoGUI.panelTrackers.add(new JCheckBox(c.getSimpleName()));
        fidoGUI.buttonSelectDownloadLocation.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                //
                //Create a file chooser
                final JFileChooser fc = new JFileChooser();
                fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

                //In response to a button click:
                //int returnVal = fc.showOpenDialog();
                fc.setDialogTitle("Choose you save location for torrent files");

                // String saveLocationFromSettings = FidoCommonUtils.getPropertyValue("fido.directory.torrents");
                String path = fidoGUI.labelSelectedDownloadLocation.getText();

                File existingFile = new File(path);
                fc.setSelectedFile(existingFile);
                //Handle open button action.
                if (e.getSource() == fidoGUI.buttonSelectDownloadLocation) {
                    int returnVal = fc.showOpenDialog(fidoGUI);

                    if (returnVal == JFileChooser.APPROVE_OPTION) {
                        File file = fc.getSelectedFile();
                        //This is where a real application would open the file.
                        log(file.getAbsolutePath());
                        log("Opening: " + file.getName() + ".");

                        //Make sure the path ends with a File.separator.
                        String newPath = file.getAbsolutePath();
                        if (!File.separator.equals("" + newPath.charAt(newPath.length() - 1))) {
                            newPath += File.separator;
                        }
                        fidoGUI.labelSelectedDownloadLocation.setText(newPath);
                    } else {
                        log("Open command cancelled by user.");
                    }
                }
            }
        });

        fidoGUI.buttonRunNow.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {

                Thread thread = new Thread(new runNow());
                thread.isDaemon();
                thread.start();

            }
        });

        fidoGUI.trayIcon.displayMessage("Fido", "Fido ver: " + FidoCommonUtils.getVersion() + " is started", TrayIcon.MessageType.INFO);
    }


    private void startScheduledTimer(int hours) {
        log("Timer set for every " + hours + " hours.");
        int milliseconds = hours * MILLISECONDS_PER_HOUR;
        stopScheduledTimer();
        scheduledTimer = new java.util.Timer();
        scheduledTimer.schedule(new TimerTask() {
            public void run() {

                Thread thread = new Thread(new runNow());
                thread.isDaemon();
                thread.start();
            }
        }, 5000, milliseconds);
    }

    private void log(final String s) {
        new Thread() {
            public void run() {
                fidoGUI.textArea2.setText(DateUtils.now("H:mm:ss: ") + s + "\n" + fidoGUI.textArea2.getText());
            }
        }.start();

    }

    private void stopScheduledTimer() {


        if (scheduledTimer != null) {
            scheduledTimer.cancel();
        }


    }


    private void checkVersion() {

        String page = FidoCommonUtils.getWebPage("http://code.google.com/p/fido/wiki/Version");

        String regex = "-version-(.*?)-version-";

        double newVersion;
        Pattern pattern = Pattern.compile(regex);
        Matcher m = pattern.matcher(page);
        if (m.find()) {

            newVersion = Double.valueOf(m.group(1));
            if (newVersion > FidoCommonUtils.getVersion()) {
                log("You have version:" + FidoCommonUtils.getVersion() + ". New version is:" + newVersion);
                log("Fido version" + newVersion + "can be found at http://code.google.com/p/fido/");

                JOptionPane.showMessageDialog(null, "Fido version" + newVersion + "can be found at http://code.google.com/p/fido/");
            } else {
                log("Fido is up to date.");
            }
        } else {
            log("Couldn't find current fido version.");
        }


    }

    @Override
    public void startUserInterface(String[] args) {
        fidoGUI.setVisible(true);
    }

    @Override
    public void showMessage(String message) {
        log(message);
    }

    @Override
    public void fidoStartedFetching() {
    }

    @Override
    public void fidoFinishedSearching() {
    }

    @Override
    public void fidoIsAttemptingToFetch(Movie movie) {
        ListModel wishListModel = fidoGUI.lWishList.getModel();
        for (int i = 0; i < wishListModel.getSize(); i++) {
            String movieName = wishListModel.getElementAt(i).toString();
            if (movie.getName().equals(movieName)) {
                fidoGUI.lWishList.setSelectedIndex(i);
                fidoGUI.lWishList.ensureIndexIsVisible(i);
            }
        }

    }

    @Override
    public void fidoFetchedMovie(Movie movie, Torrent torrent) {
        fidoGUI.trayIcon.displayMessage(null, movie.getName() + " found", TrayIcon.MessageType.INFO);
        downloadedModel.addElement(movie.getName() + " (" + torrent.getTorrentSiteName() + ")");
        //TODO: wishListedModel.removeElement(movie.getName());
    }

    @Override
    public void fidoCouldNotFetch(Movie movie, String torrentSitesName) {
    }


    private class runNow implements Runnable {
        public final void run() {
            if (!isBusy) {
                try {
                    isBusy = true;
                    fidoGUI.progressBar.setIndeterminate(true);
                    torrentSites.makeSureAllSelectedTorrentSitesAreConfiguredGUI();

                    fido.setDownloadLocation(fidoGUI.labelSelectedDownloadLocation.getText());

                    MmdbUtils.setUsername(fidoGUI.textUserName.getText());
                    MmdbUtils.setPassword(fidoGUI.textPassword.getText());
                    User user = MmdbUtils.loginUser();
                    //TODO: A class for storing Movies, instead of List<Movie>
                    java.util.List<Movie> wishListedMovies = MmdbUtils.getWishlistedMovies(user);

                    //Print wish list
                    DefaultListModel wishListedModel = new DefaultListModel();
                    fidoGUI.lWishList.setModel(wishListedModel);
                    fidoGUI.lDownloadedMoviesList.setModel(downloadedModel);
                    for (Movie currentMovie : wishListedMovies) {
                        wishListedModel.addElement(currentMovie.getName());
                    }

                    fido.goFetch(wishListedMovies);
                } catch (Exception e) {
                    showMessage("Error while fetching: " + e.getMessage());
                } finally {
                    isBusy = false;
                    fidoGUI.progressBar.setIndeterminate(false);
                }
            } else {
                showMessage("Already running..");
            }
        }
    }


    private class TimerGroupListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            log(e.getActionCommand());

            if (e.getActionCommand().equals("1 hour")) {
                startScheduledTimer(1);
            } else if (e.getActionCommand().equals("3 hours")) {
                startScheduledTimer(3);
            } else if (e.getActionCommand().equals("12 hours")) {
                startScheduledTimer(12);
            } else if (e.getActionCommand().equals("24 hours")) {
                startScheduledTimer(24);
            } else if (e.getActionCommand().equals("No timer")) {
                stopScheduledTimer();
            }


        }
    }

    private class CheckVersionListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            checkVersion();
        }
    }


}
